#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdbool.h>
#include "../dbms/param.h"
#include "z_logger.h"

static _Bool is_tm_reserve_keys(const char *key) {
    static const char *reserve_keys[] = {PARAM_METHOD, PARAM_TABLE, PARAM_ID, PARAM_KEY, PARAM_TAG, PARAM_SEGMENT};

    for (int j = 0; j < sizeof(reserve_keys) / sizeof(reserve_keys[0]); ++j) {
        if (0 == strcasecmp(reserve_keys[j], key)) {
            return true;
        }
    }

    return false;
}

static _Bool is_reserve_keys(const char *key) {
    static const char *reserve_keys[] = {PARAM_METHOD, PARAM_TABLE, PARAM_ID, PARAM_KEY};

    for (int j = 0; j < sizeof(reserve_keys) / sizeof(reserve_keys[0]); ++j) {
        if (0 == strcasecmp(reserve_keys[j], key)) {
            return true;
        }
    }

    return false;
}

static char *re_sql(const query_param_t *param, char *sql, size_t size) {
    char *end = sql + size;
    const char *table = param_get_table(param);
    if (!strcmp("thing_model", table)) {
        const char *segment = param_get_segment(param);
        const char *tag = param_get_tag(param);
        const char *product_id = param_get_string(param, "product");

        sql += snprintf(sql, end - sql, "INSERT INTO %s(idx,product,segment,tag", table);
        for (int i = 0; i < param->size; i++) {
            if (is_tm_reserve_keys(param->key[i])) continue;
            sql += snprintf(sql, end - sql, ", %s", param->key[i]);
        }
        sql += snprintf(sql, end - sql, ") VALUES (-1,'%s'", product_id);
        sql += snprintf(sql, end - sql, ", %s", segment);
        sql += snprintf(sql, end - sql, ", %s", tag);
        for (int i = 0; i < param->size; i++) {
            if (is_tm_reserve_keys(param->key[i])) continue;
            const query_value_t *value = &param->val[i];
            if (cJSON_String == value->type) {
                sql += snprintf(sql, end - sql, ",'%s'", value->str_val);
            } else if (cJSON_Number == value->type) {
                sql += snprintf(sql, end - sql, ",%f", value->dbl_val);
            } else {
                sql += snprintf(sql, end - sql, ",Null");
            }
        }
        sql += snprintf(sql, end - sql, ")");
    } else {
        const char *id = param_get_string(param, "id");
        sql += snprintf(sql, end - sql, "INSERT INTO %s(id", table);
        for (int i = 0; i < param->size; i++) {
            if (is_reserve_keys(param->key[i])) continue;
            sql += snprintf(sql, end - sql, ", %s", param->key[i]);
        }

        sql += snprintf(sql, end - sql, ") VALUES ('%s'", id);


        for (int i = 0; i < param->size; i++) {
            if (is_reserve_keys(param->key[i])) continue;
            const query_value_t *value = &param->val[i];
            if (cJSON_String == value->type) {
                sql += snprintf(sql, end - sql, ",'%s'", value->str_val);
            } else if (cJSON_Number == value->type) {
                sql += snprintf(sql, end - sql, ",%f", value->dbl_val);
            } else {
                sql += snprintf(sql, end - sql, ",Null");
            }
        }
        sql += snprintf(sql, end - sql, ")");
    }
    return sql;
}


static void func(int file_line, int cnt, char buff[file_line][cnt][500], char *table_name) {
    query_param_t param;
    for (int j = 1; j < file_line; j++) {
        bzero(&param, sizeof(param));
        param.key[0] = "table";
        query_value_t *value = &param.val[0];
        value->type = cJSON_String;
        value->str_val = table_name;
        log_trace("key=%s, val=%s", param.key[param.size], value->str_val);
        param.size++;
        for (int i = 0; i < cnt && param.size < PARAM_MAX; ++i) {
            param.key[param.size] = buff[0][i];
            value = &param.val[param.size];
            value->type = cJSON_String;
            value->str_val = buff[j][i];
            log_trace("key=%s, val=%s", param.key[param.size], value->str_val);
            param.size++;
        }
        char sql[1024] = {};
        re_sql(&param, sql, sizeof(sql));
        printf("\n---------------------------------\n");
        printf("sql = %s", sql);
    }
}

int readfile_csv(char *filename) {
    FILE *fp = fopen(filename, "rb");
    static int file_line = 1;
    fseek(fp, 0, SEEK_END);
    long flen = ftell(fp);
    printf("len = %ld\n", flen);
    fseek(fp, 0, SEEK_SET);
    int fd = fileno(fp);//文件指针转文件描述符
    if (fd == -1) {
        printf("转换失败\n");
        return -1;
    }
    char *file_addr = mmap(NULL, flen, PROT_READ, MAP_SHARED, fd, 0);//内存映射
    fclose(fp);
    close(fd);
    if (file_addr == NULL) {
        printf("映射失败\n");
        return -2;
    }
    /*统计行*/
    char *p = file_addr;
    while (*p) {
        if (*p == '\n') {
            p = strstr(p, ",");
            if (p == NULL)break;
            file_line++;
        } else p++;
    }
    printf("行：%d\n", file_line);//统计行
    /*统计列*/
    int cnt = 0;
    p = file_addr;
    while (*p && *p != '\n') {
        while (*p != '\n' && *p != ',' && *p)p++;
        cnt++;
        if (*p == '\n')break;
        p++;
    }
    printf("列:%d\n", cnt);
    /*将.csv文件数据保存到数组中*/
    char buff[file_line][cnt][500];
    int i, j;
    p = file_addr;
    for (i = 0; i < file_line; i++) {
        for (j = 0; j < cnt; j++) {
            int index = 0;
            while (*p != '\n' && *p != ',' && *p) {
                buff[i][j][index++] = *p;
                p++;
            }
            if (*p == ',') {
                p++;
                buff[i][j][index++] = '\0';
            }
            if (*p == '\n') {
                p++;
                break;
            }
        }
    }
    munmap(file_addr, flen);/*取消映射*/
    char *table_name = "device";
    func(file_line, cnt, buff, table_name);
    return 0;
}

int main() {
    readfile_csv("1.csv");
    return 0;
}
